package hu.mapro.gwtui.server;

import hu.mapro.gwtui.client.data.SortField;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.AbstractQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Fetch;
import javax.persistence.criteria.FetchParent;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;

import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

public class DataUtils {

	public static <T> List<Order> createOrder(
			CriteriaBuilder criteriaBuilder,
			Root<T> root,
			List<SortField> sortConfig
	) {
		SortBuilderImpl<T> sb = new SortBuilderImpl<T>(root);
		
    	List<Order> order = Lists.newArrayList();
    	for (SortField sortField : sortConfig) {
    		sortField.createExpression(sb);
    		
    		Order jpaOrder = null;
    		
    		if (sortField.getAscending()) {
    			jpaOrder = criteriaBuilder.asc(sb.getExpression());
    		} else {
    			jpaOrder = criteriaBuilder.desc(sb.getExpression());
    		}
    		
    		order.add(jpaOrder);
    	}
    	return order;
	}

	
	
//	public static <T> PageResult<T> query(
//			EntityManager em,
//			Class<T> clazz,
//			int firstResult, 
//			int maxResults, 
//			SortConfig sortConfig			
//	) {
//		CriteriaBuilder builder = em.getCriteriaBuilder();
//		
//    	CriteriaQuery<Long> countQuery = builder.createQuery(Long.class);
//    	Root<T> countRoot = countQuery.from(clazz);
//		countQuery.select(builder.count(countRoot));
//		long count = em.createQuery(countQuery).getSingleResult();
//    	
//    	
//		builder = em.getCriteriaBuilder();
//    	CriteriaQuery<T> query = builder.createQuery(clazz);
//    	Root<T> root = query.from(clazz);
//    	query.orderBy(DataUtils.createOrder(builder, root, sortConfig.getFields()));
//    	TypedQuery<T> typedQuery = em.createQuery(query);
//		typedQuery.setFirstResult(firstResult);
//		typedQuery.setMaxResults(maxResults);
//		List<T> records = typedQuery.getResultList();
//		return new PageResultBean<T>(records, count, firstResult);
//	}

	public static <T> Long count(
			EntityManager em,
			Class<T> clazz
	) {
		CriteriaBuilder builder = em.getCriteriaBuilder();
		
    	CriteriaQuery<Long> countQuery = builder.createQuery(Long.class);
    	Root<T> countRoot = countQuery.from(clazz);
		countQuery.select(builder.count(countRoot));
		return em.createQuery(countQuery).getSingleResult();
	}

	
	public static <T> List<T> list(
			EntityManager em,
			Class<T> clazz,
			int firstResult, 
			int maxResults, 
			List<SortField> sortConfig			
			) {
		CriteriaBuilder builder = em.getCriteriaBuilder();
		CriteriaQuery<T> query = builder.createQuery(clazz);
		Root<T> root = query.from(clazz);
		query.orderBy(DataUtils.createOrder(builder, root, sortConfig));
		TypedQuery<T> typedQuery = em.createQuery(query);
		typedQuery.setFirstResult(firstResult);
		typedQuery.setMaxResults(maxResults);
		List<T> records = typedQuery.getResultList();
		return records;
	}

	public static <T> List<T> list(
			EntityManager em,
			Class<T> clazz
			) {
		CriteriaBuilder builder = em.getCriteriaBuilder();
		CriteriaQuery<T> query = builder.createQuery(clazz);
		query.from(clazz);
		TypedQuery<T> typedQuery = em.createQuery(query);
		List<T> records = typedQuery.getResultList();
		return records;
	}
	
	
}
